package utils;

import java.lang.reflect.*;
import java.sql.*;
import java.util.*;

public class JDBCUtils {
  /**
   * 将查询抽象成方法
   *
   * @param clazz 类的类
   * @param sql   SQL语句
   * @param args  参数
   * @param <T>   泛型
   * @return 泛型数组
   */
  public static <T> ArrayList<T> queryFromTable(Class<T> clazz, String sql, Object... args) { // 泛型方法
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null; // 保存查询结果
    ArrayList<T> ts = new ArrayList<>();  // 表对应的对象列表
    try {
      conn = JDBCUtils.getConnection();
      ps = conn.prepareStatement(sql);  // 语句传进statement中
      for (int i = 0; i < args.length; i++) {
        ps.setObject(i + 1, i);  // 参数1为`?`的位置,参数2为该位置参数的值
      }
      rs = ps.executeQuery(); // ResultSet 获取查询结果
      ResultSetMetaData metaData = rs.getMetaData();  // 获取查询出来的元数据
      int columnCount = metaData.getColumnCount(); // 获取列的个数

      // 用于保存所有属性,并通过反射获取对应的Field
      Field[] declaredFields = new Field[columnCount];
      for (int i = 0; i < columnCount; i++) {
        String columnLabel = metaData.getColumnLabel(i + 1);
        Field declaredField = clazz.getDeclaredField(columnLabel);
        declaredField.setAccessible(true);
        declaredFields[i] = declaredField;
      }

      // 遍历所有行
      while (rs.next()) {
        T t = clazz.getDeclaredConstructor().newInstance();  // 实例化泛型参数的对象
        // 遍历每一列,并取出值
        for (int i = 0; i < columnCount; i++) {
          Object columnValue = rs.getObject(i + 1);
          if (columnValue != null) {
            declaredFields[i].set(t, columnValue);  // 设置对象属性
          }
        }
        ts.add(t);  // 添加进list里
      }
      return ts;
    } catch (
            Exception e) {
      e.printStackTrace();
    } finally {
      JDBCUtils.closeSource(conn);
      JDBCUtils.closeSource(ps);
      JDBCUtils.closeSource(rs);
    }
    return null;
  }

  /**
   * 自带连接的增删改操作
   *
   * @param conn
   * @param sql
   * @param args
   * @throws SQLException
   */
  public static void updateDatabase(Connection conn, String sql, Object... args) {
    PreparedStatement ps = null;
    try {
      ps = conn.prepareStatement(sql);
      for (int i = 0; i < args.length; i++) {
        ps.setObject(i + 1, args[i]);
      }
      ps.execute();
    } catch (SQLException throwables) {
      throwables.printStackTrace();
    } finally {
      closeSource(ps);
    }
  }

  /**
   * 封装好了增删改SQL语句的操作
   *
   * @param sql  SQL指令
   * @param args 参数列表
   */
  public static void updateDatabase(String sql, Object... args) {
    Connection conn = null;
    PreparedStatement ps = null;
    try {
      conn = getConnection();
      ps = conn.prepareStatement(sql);
      for (int i = 0; i < args.length; i++) {
        ps.setObject(i + 1, args[i]);
      }
      ps.execute();
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      closeSource(conn);
      closeSource(ps);
    }
  }

  /**
   * 导入JDBC连接操作
   *
   * @return
   * @throws Exception
   */
  public static Connection getConnection() throws Exception {
    //  导入properties文件
    Properties config = new Properties();
    config.load(ClassLoader.getSystemClassLoader().getResourceAsStream("config.properties"));

    Class<?> driverClass = Class.forName(config.getProperty("Driver"));
    // 底层已经做了，所以不需要自己注册了
    // Driver driver = (Driver) driverClass.newInstance();
    // DriverManager.registerDriver(driver);

    String url = config.getProperty("url");
    return DriverManager.getConnection(url, config);
  }

  /**
   * 关闭资源操作
   *
   * @param source
   */
  public static void closeSource(AutoCloseable source) {
    try {
      if (source != null) {
        source.close();
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

}
